<template>
  <div>
    <el-header style="height: 60px;line-height: 60px;">
      <el-button-group>
        <el-button icon="el-icon-connection" size="mini" @click="getServerList">连接</el-button>
        <el-button icon="el-icon-coin" size="mini" @click="showDbList = true">数据库</el-button>
        <el-button icon="el-icon-close" size="mini" @click="closeDb">关闭</el-button>
      </el-button-group>
    </el-header>

    <el-container style="margin-top: 1px;">
      <el-tabs tab-position="left" v-model="currentDbIndex" @tab-click="clickDb" style="width: 100%;">
        <el-tab-pane v-for="(db, index) in databases" :key="index" :name="String(index)">
          <span slot="label" @dblclick="dbAlias"><i class="el-icon-coin"></i> {{db.alias}}</span>

          <el-container>
            <div style="height: 100vh; overflow-y: auto; background-color: #f1f1f1;">
              <el-input
                placeholder="查找表名"
                spellCheck=false
                autocomplete="off"
                autoCapitalize="off"
                autoCorrect="off"
                size="mini"
                v-model="filterText">
                <el-button slot="append" icon="el-icon-plus" @click="addTable"></el-button>
              </el-input>
              <el-tree
                class="table_menu filter-tree"
                :data="db.tableFilter"
                :props="{label: 'name'}"
                @node-click="clickTable"
                ref="tableTree">
                <template slot-scope="{ node }">
                  <div class="connect_tree_node">
                    <el-link icon="el-icon-s-grid">{{ node.label }}</el-link>
                  </div>
                </template>
              </el-tree>
            </div>

            <el-container style="width: 90vw;">
              <el-tabs v-model="editTabsValue" type="card" closable @tab-click="clickTab" @tab-remove="removeTab" style="width: 100%;">
                <el-tab-pane
                  :key="index"
                  v-for="(tabItem, index) in editTabs"
                  :label="tabItem.title"
                  :name="tabItem.name"
                >
                  <el-button-group class="edit_tab_btn">
                    <el-button icon="el-icon-document" size="mini" :type="tabItem.type == EditTabType.SQL ? 'primary' : ''" plain @click="tab_operate(EditTabType.SQL)">浏览</el-button>
                    <el-button icon="el-icon-menu" size="mini" :type="tabItem.type == EditTabType.STRUCTURE || tabItem.type == EditTabType.TABLE ? 'primary' : ''" plain @click="tab_operate(EditTabType.STRUCTURE)">结构</el-button>
                    <el-button icon="el-icon-document-add" size="mini" :type="tabItem.type == EditTabType.UPDATE ? 'primary' : ''" plain @click="tab_operate(EditTabType.UPDATE)">插入</el-button>
                    <el-button icon="el-icon-s-operation" size="mini" plain @click="alert">操作</el-button>
                  </el-button-group>
                  <div v-if="tabItem.type == EditTabType.SQL">
                    <div class="codemirror">
                      <codemirror v-model="tabItem.sql" :options="cmOption"></codemirror>
                    </div>
                    
                    <el-button size="mini" class="submit_btn" @click="execute(1)">执行</el-button>

                    <div style="height: 95vh;overflow-y: auto;">
                      <el-table
                        :data="tabItem.result"
                        border
                        show-header
                        class="datatable result"
                        highlight-current-row
                        :size="medium"
                        >
                        <el-table-column v-if="tabItem.allow_edit == 1" width="100">
                          <template slot-scope="scope">
                            <el-button type="text" size="small" :name="scope.$index" @click="tab_operate(EditTabType.UPDATE, scope.row)">编辑</el-button>
                            <el-button type="text" size="small" @click="deleteRow(scope.row)">删除</el-button>
                          </template>
                        </el-table-column>
                        <el-table-column v-for="(column, index) in tabItem.resultColumns"
                          :key="index"
                          :label="column"
                          :prop="column"
                          :min-width="tableWidth(column)"
                          >
                          <template slot-scope="scope">
                            <div @dblclick="cellDbClick($event, tabItem.allow_edit, scope.row, column, scope.$index)">
                              <p class="descStyle" :class="{ 'is_null': scope.row[column][0] === 'NULL' }">{{ scope.row[column][1] | displayCell }}</p>
                            </div>
                          </template>
                        </el-table-column>
                      </el-table>
                    </div>
                    <el-pagination
                      :page-size="tabItem.pagesize"
                      layout="total, sizes, prev, pager, next"
                      @size-change="handleSizeChange"
                      @current-change="execute"
                      :page-sizes="[25, 50, 100, 250, 500]"
                      :current-page.sync="tabItem.page"
                      :total="tabItem.total">
                    </el-pagination>
                  </div>

                  <div v-else-if="tabItem.type == EditTabType.TABLE">
                    <el-container>
                    <el-table
                      :data="tabItem.tableForm.columns"
                      class="datatable"
                      :size="medium"
                      >
                      <el-table-column v-for="(item, index) in tableStructure"
                        :key="index"
                        :label="item.label"
                        :prop="item.prop"
                        :min-width="item.width"
                        >
                        <template slot-scope="scope">
                          <el-input
                            v-if="item.prop == 'name'"
                            v-model="tabItem.tableForm.columns[scope.$index].name"
                            size="mini"
                            autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
                            @focus="addColumn(scope.$index)"
                          />

                          <div v-if="item.prop == 'name'">
                            <el-input v-model="tabItem.tableForm.columns[scope.$index].old_name" v-show="false" />
                            <el-input v-model="tabItem.tableForm.columns[scope.$index].after" v-show="false" />
                          </div>

                          <el-select v-if="item.prop == 'type'"
                            v-model="tabItem.tableForm.columns[scope.$index].type" 
                            filterable
                            size="mini"
                            placeholder="请选择">
                            <el-option
                              v-for="op in item.options.options"
                              :key="op"
                              :label="op"
                              :value="op">
                            </el-option>
                            <el-option-group
                              v-for="group in item.options.group"
                              :key="group.label"
                              :label="group.label">
                              <el-option
                                v-for="gop in group.options"
                                :key="gop"
                                :label="gop"
                                :value="gop">
                              </el-option>
                            </el-option-group>
                          </el-select>

                          <el-input
                            v-if="item.prop == 'length'"
                            v-model="tabItem.tableForm.columns[scope.$index].length"
                            size="mini"
                            autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
                          />

                          <el-select v-if="item.prop == 'value'"
                            v-model="tabItem.tableForm.columns[scope.$index].value" 
                            size="mini"
                            placeholder="请选择">
                            <el-option
                              v-for="op in item.options"
                              :key="op.value"
                              :label="op.label"
                              :value="op.value">
                            </el-option>
                          </el-select>
                          <el-input
                            v-if="item.prop == 'value' && tabItem.tableForm.columns[scope.$index].value == 'DEFINED'"
                            v-model="tabItem.tableForm.columns[scope.$index].definedValue"
                            size="mini"
                            autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
                          />

                          <el-select v-if="item.prop == 'attribute'"
                            v-model="tabItem.tableForm.columns[scope.$index].attribute" 
                            size="mini"
                            placeholder="请选择">
                            <el-option
                              v-for="op in item.options"
                              :key="op"
                              :label="op"
                              :value="op">
                            </el-option>
                          </el-select>

                          <el-checkbox v-if="item.prop == 'null'" true-label="1" false-label="0" v-model="tabItem.tableForm.columns[scope.$index].null"></el-checkbox>

                          <el-checkbox v-if="item.prop == 'primary'" true-label="1" false-label="0" v-model="tabItem.tableForm.columns[scope.$index].primary"></el-checkbox>

                          <el-checkbox v-if="item.prop == 'auto_increment'" true-label="1" false-label="0" v-model="tabItem.tableForm.columns[scope.$index].auto_increment"></el-checkbox>

                          <el-input
                            v-if="item.prop == 'comment'"
                            v-model="tabItem.tableForm.columns[scope.$index].comment"
                            size="mini"
                            autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
                          />
                        </template>
                      </el-table-column>
                    </el-table>
                    </el-container>

                    <el-container v-if="tabItem.tableInfoSwitch">
                    <el-table class="datatable" :data="[0]" :size="medium">
                      <el-table-column
                        v-for="(item, index) in tableInfo"
                        :key="index"
                        :label="item.label"
                        :prop="item.prop"
                        :width="item.width"
                        >
                        <template slot-scope="scope">
                          <el-input
                            v-if="item.prop == 'name' && scope.$index == 0"
                            v-model="tabItem.tableForm.name"
                            size="mini"
                            autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
                          />

                          <el-select v-if="item.prop == 'collation'"
                            v-model="tabItem.tableForm.collation" 
                            filterable
                            size="mini"
                            placeholder="请选择">
                            <el-option-group
                              v-for="group in item.options"
                              :key="group.label"
                              :label="group.label">
                              <el-option
                                v-for="op in group.options"
                                :key="op"
                                :label="op"
                                :value="op">
                              </el-option>
                            </el-option-group>
                          </el-select>

                          <el-select v-if="item.prop == 'engine'"
                            v-model="tabItem.tableForm.engine" 
                            size="mini"
                            placeholder="请选择">
                            <el-option
                              v-for="op in item.options"
                              :key="op"
                              :label="op"
                              :value="op">
                            </el-option>
                          </el-select>

                          <el-input
                            v-if="item.prop == 'comment'"
                            v-model="tabItem.tableForm.comment"
                            size="mini"
                            spellCheck=false
                            autoCapitalize="off" autoCorrect="off" autocomplete="off"
                          />
                        </template>
                      </el-table-column>
                    </el-table>
                    </el-container>

                    <el-button size="mini" class="submit_btn" @click="createOrAlterTable(true)">预览</el-button>
                    <el-button size="mini" class="submit_btn" @click="createOrAlterTable(false)">保存</el-button>
                  </div>

                  <div v-else-if="tabItem.type == EditTabType.UPDATE">
                    <el-table
                      :data="tabItem.tableColumns"
                      :size="medium"
                      style="width: 700px;"
                      >
                      <el-table-column v-for="(item, index) in updateStructure"
                        :key="index"
                        :label="item.label"
                        :prop="item.prop"
                        :width="item.width"
                        >
                        <template slot-scope="scope">
                          <div v-if="item.prop == 'name'">
                            {{ scope.row['name'] }}
                          </div>
                          <div v-if="item.prop == 'type'">
                            {{ scope.row['type'] }}
                          </div>
                          <el-checkbox v-if="item.prop == 'nullable'" true-label="NULL" false-label="String" v-model="tabItem.updateForm.nullable[scope.row['name']]"></el-checkbox>
                          <el-input
                            v-if="item.prop == 'value'"
                            type="textarea"
                            :rows="1"
                            v-model="tabItem.updateForm.new[scope.row['name']]"
                            resize="vertical"
                            style="width: 300px"
                            size="mini"
                            spellCheck=false
                            autoCapitalize="off" autoCorrect="off" autocomplete="off"
                          />
                        </template>
                      </el-table-column>
                    </el-table>
                    <el-button size="mini" class="submit_btn" @click="updateOrInsert">保存</el-button>
                  </div>

                  <div v-else-if="tabItem.type == EditTabType.STRUCTURE">
                    <el-table
                      :data="tabItem.tableColumns"
                      :size="medium"
                      class="altertable"
                      >
                      <el-table-column v-for="(item, index) in alterStructure"
                        :key="index"
                        :label="item.label"
                        :prop="item.prop"
                        :width="item.width"
                        >
                        <template slot-scope="scope">
                          <div v-if="item.prop == 'name' && scope.row['comment'].length > 0">
                            <el-tooltip class="item" effect="dark" :content="scope.row['comment']" placement="right">
                              <el-link :underline="false">{{ scope.row[item.prop] }}</el-link>
                            </el-tooltip>
                          </div>
                          <div v-else>
                            {{ scope.row[item.prop] }}
                          </div>
                        </template>
                      </el-table-column>
                      <el-table-column
                        label="操作"
                        width="100">
                        <template slot-scope="scope">
                          <el-button type="text" size="small" @click="editColumn(scope.row)">修改</el-button>
                          <el-button type="text" size="small" @click="delColumn(scope.row)">删除</el-button>
                        </template>
                      </el-table-column>
                    </el-table>

                    <div class="altertable" style="margin: 20px 10px;">
                      添加 <el-input v-model="tabItem.addColumnNum" size="mini" style="width:50px"></el-input> 个字段 
                      <el-select v-model="tabItem.addColumnAfter" size="mini" placeholder="请选择">
                        <el-option
                          v-for="item in addColumnSelect(tabItem.tableColumns)"
                          :key="item.name"
                          :label="item.label"
                          :value="item.name">
                        </el-option>
                      </el-select>
                      <el-button size="mini" @click="addColumnAfter">执行</el-button>
                    </div>

                    <h3 style="font-weight: 400;color: #1f2f3d;margin: 50px 0 10px 5px;">索引</h3>
                    <el-table
                      :data="tabItem.tableIndexs"
                      :size="medium"
                      class="altertable"
                      >
                      <el-table-column label="键名" prop="Key_name" width="100">
                        <template slot-scope="scope">
                          {{ scope.row.Key_name }}
                        </template>
                      </el-table-column>
                      <el-table-column label="类型" prop="Index_type" width="100">
                        <template slot-scope="scope">
                          {{ scope.row.Index_type }}
                        </template>
                      </el-table-column>
                      <el-table-column label="唯一" prop="Non_unique" width="100">
                        <template slot-scope="scope">
                          <div v-if="scope.row.Non_unique == 0">是</div>
                          <div v-else>否</div>
                        </template>
                      </el-table-column>
                      <el-table-column label="字段" prop="Column_name" width="200">
                        <template slot-scope="scope">
                          {{ scope.row.Column_name }}
                        </template>
                      </el-table-column>
                    </el-table>
                    <el-divider></el-divider>
                  </div>
                </el-tab-pane>
              </el-tabs>
            </el-container>

          </el-container>
        </el-tab-pane>
        
      </el-tabs>
    </el-container>

    <!-- 弹层修改值 -->
    <div v-if="tableEditor.index >= 0"
      @keydown.esc="handleEscape()"
      class="overlay" :style="overlay">
      <el-checkbox v-model="tableEditor.valueNull">NULL</el-checkbox>
      <div style="float: right;">按Esc取消</div>
      <el-input type="textarea"
        v-focus
        autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false
        resize="vertical"
        style="width: 300px;z-index: 1000;"
        :rows="1"
        v-model="tableEditor.newValue"
      ></el-input>
    </div>

    <el-dialog title="连接服务器" :visible.sync="showServerList" :close-on-click-modal="false" width="400px">
      <el-dialog
        width="400px"
        title="添加服务器"
        :visible.sync="showCreateServer"
        :close-on-click-modal="false"
        append-to-body>
        <el-form :model="serverForm" label-width="70px" size="mini" ref="serverForm">
          <el-form-item prop="index" v-show="false"></el-form-item>
          <el-form-item label="名称" prop="label" :rules="[{ required: true, message: '名称不能为空'}]">
            <el-input v-model="serverForm.label" autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false style="width: 250px;"></el-input>
          </el-form-item>
          <el-form-item label="地址" prop="host" :rules="[{ required: true, message: '地址不能为空'}]">
            <el-input v-model="serverForm.host" autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false style="width: 150px;"></el-input> : <el-input v-model="serverForm.port" autoCapitalize="off" autoCorrect="off" autocomplete="off" style="width: 80px;"></el-input>
          </el-form-item>
          <el-form-item label="用户名" prop="user" :rules="[{ required: true, message: '用户名不能为空'}]">
            <el-input v-model="serverForm.user" autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false style="width: 250px;"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password" :rules="[{ required: true, message: '密码不能为空'}]">
            <el-input v-model="serverForm.password" autoCapitalize="off" autoCorrect="off" autocomplete="off" spellCheck=false show-password style="width: 250px;"></el-input>
          </el-form-item>
        </el-form>
        <div slot="footer" class="dialog-footer">
          <el-button @click="showCreateServer = false" size="mini">取消</el-button>
          <el-button type="primary" @click="addServer" size="mini">保存</el-button>
        </div>
      </el-dialog>

      <draggable v-model="serverList" class="connect_list" @end="serverOnEnd">
        <div
          v-for="(data, index) in serverList"
          :key="index"
          :class="{ 'selected': selectedNode === index }"
          @click="selectNode(index)"
          class="connect_tree_node"
        >
          <span><i class="el-icon-monitor db_tree_icon"></i>{{ data.label }}</span>
          <div class="connect_tree_opt_right">
            <el-link class="opt_item" icon="el-icon-edit" @click="editServer(data)"></el-link>
            <el-link class="opt_item" icon="el-icon-close" @click="deleteServer(data)"></el-link>
          </div>
        </div>
      </draggable>
      <div slot="footer" class="dialog-footer">
        <el-button @click="addServerDialog" size="mini">新建</el-button>
        <el-button type="primary" @click="connectServer" size="mini" :disabled="serverListSelected === -1">打开</el-button>
      </div>
    </el-dialog>

    <el-dialog title="打开数据库" :visible.sync="showDbList" :close-on-click-modal="false" width="300px">
      <el-input
                placeholder="查找数据库"
                autocomplete="off"
                autoCapitalize="off"
                autoCorrect="off"
                spellCheck=false
                size="mini"
                v-model="filterDb">
              </el-input>
      <div class="connect_list">
        <div
          v-for="(data, index) in dbListFilter"
          :key="data.label"
          :class="{ 'selected': selectedNode === index }"
          @click="selectNode(index)"
          class="connect_tree_node"
        >
          <span><i class="el-icon-coin db_tree_icon"></i>{{ data.label }}</span>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="showDbList = false" size="mini">取消</el-button>
        <el-button type="primary" @click="connectDb" size="mini" :disabled="serverListSelected === -1">打开</el-button>
      </div>
    </el-dialog>
  </div>
  
</template>

<script>

import { server_list, add_server, del_server, sort_server, db_list, connect_db, execute_sql, create_table_preview, create_table, alter_table_preview, alter_table, table_columns, table_index } from "@/api/mysql";
import { EditTabType, TableForm, ColumnForm, ColumnType, ColumnValue, Collation, Engine, ColumnAttribute } from "@/constants/mysql";
import draggable from 'vuedraggable';
import { codemirror } from 'vue-codemirror';
import 'codemirror/lib/codemirror.css';

import 'codemirror/mode/sql/sql.js'; // 加载 SQL 模式
import 'codemirror/addon/edit/matchbrackets.js'
import 'codemirror/addon/search/searchcursor.js'
import 'codemirror/theme/solarized.css'; // 引入主题


export default {
  name: 'TablePage',
  data() {
    return {
      showServerList: false,
      showDbList: false,
      showCreateServer: false,
      currentServerName: '',
      currentDbIndex: '0',
      currentTableName: '',
      pagesize: 25,
      filterText: '',
      filterDb: '',
      serverList: [],
      selectedNode: -1,
      dbList: [],
      dbListFilter: [],
      databases: [],
      editTabsValue: '1',
      editTabs: [],
      tableEditor: {
        index: -1,
        column: '',
        oldValue: '',
        row: {},
        valueNull: false,
      },
      serverForm: {},
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      overlay: {},
      tableInfo: [
        {
          prop: 'name',
          label: '表名',
          width: 150,
        },
        {
          prop: 'collation',
          label: '字符集',
          options: Collation,
          width: 150,
        },
        {
          prop: 'engine',
          label: '存储引擎',
          options: Engine,
          width: 120,
        },
        {
          prop: 'comment',
          label: '表注释',
          width: 200,
        },
      ],
      tableStructure: [
        {
          prop: 'name',
          label: '字段名',
          width: 150,
        },
        {
          prop: 'type',
          label: '类型',
          options: {
            'options': ['INT', 'VARCHAR', 'TEXT', 'DATE'],
            'group': ColumnType,
          },
          width: 150,
        },
        {
          prop: 'length',
          label: '长度',
          width: 120,
        },
        {
          prop: 'value',
          label: '默认值',
          options: ColumnValue,
          width: 150,
        },
        {
          prop: 'attribute',
          label: '属性',
          options: ColumnAttribute,
          width: 150,
        },
        {
          prop: 'null',
          label: 'null',
          width: 50,
        },
        {
          prop: 'primary',
          label: '主键',
          width: 50,
        },
        {
          prop: 'auto_increment',
          label: '自增',
          width: 50,
        },
        {
          prop: 'comment',
          label: '注释',
          width: 200,
        },
      ],
      updateStructure: [
        {
          prop: 'name',
          label: '字段名',
          width: 150,
        },
        {
          prop: 'type',
          label: '类型',
          width: 150,
        },
        {
          prop: 'nullable',
          label: '空',
          width: 50,
        },
        {
          prop: 'value',
          label: '值',
          width: 310,
        },
      ],
      alterStructure: [
        {
          prop: 'name',
          label: '字段名',
          width: 150,
        },
        {
          prop: 'type',
          label: '类型',
          width: 150,
        },
        {
          prop: 'collation',
          label: '排序规则',
          width: 150,
        },
        {
          prop: 'nullable',
          label: '空',
          width: 50,
        },
        {
          prop: 'default',
          label: '默认',
          width: 100,
        },
        {
          prop: 'extra',
          label: '额外',
          width: 150,
        },
      ],
      EditTabType: EditTabType,
      cmOption: {
        autorefresh: true,
        tabSize: 4,
        mode: 'text/x-mysql',
        theme: 'solarized',
        lineNumbers: true,  // 显示行号
        line: true,
        lineWrapping: true, // 软换行
        matchBrackets: true,    // 括号匹配
        martIndent: true,   // 自动缩进
      }
    };
  },
  directives: {
    focus: {
        inserted: function (el) {
            el.querySelector('textarea').focus();
        }
    }
  },
  watch: {
    filterText(val) {
      let db = this.databases[this.currentDbIndex];
      db.filterText = val;
      if(val.length === 0){
        db.tableFilter = db.tables;
      } else {
        let res = db.tables.filter(function(item) {
          return item.name.indexOf(val) !== -1;
        })
        db.tableFilter = res;
      }
    },
    filterDb(val) {
      if(val.length === 0){
        this.dbListFilter = this.dbList
      } else {
        let res = this.dbList.filter(function(item) {
          return item.label.indexOf(val) !== -1;
        })
        this.dbListFilter = res;
      }
    },
  },
  components: {
    codemirror,
    draggable,
  },
  created() {
    this.getServerList();
  },
  mounted() {
    document.addEventListener('click', this.handleClickOutside);
  },
  beforeDestroy() {
    document.removeEventListener('click', this.handleClickOutside);
  },
  filters: {
    displayCell(value) {
      if(value.length === 0){
        return "\u00a0 \u00a0";
      }
      let val = value.replace(/\s/g, "\u00a0");
      return val.length > 50 ? val.slice(0, 50) + '...' : val;
    }
  },
  methods: {
    selectNode(index) {
      this.selectedNode = index;
    },
    filterNode(value, data) {
      if (!value) return true;
      return data.label.indexOf(value) !== -1;
    },
    resetForm(formName) {
        if (this.$refs[formName] !== undefined) {
            this.$refs[formName].resetFields();
        }
    },
    //获取server列表
    getServerList() {
      server_list().then(res => {
        this.serverList = res;
      }, (err) => {
        this.$message.error(err);
      });
      this.selectedNode = -1;
      this.showServerList = true;
    },
    serverOnEnd() {
      let sort = [];
      this.serverList.map((item) => {
        sort.push(item.label);
      });
      sort_server(sort);
    },
    //新建server配置
    addServerDialog() {
      this.showCreateServer = true;
      this.resetForm('serverForm');
      this.serverForm = {index: -1};
    },
    addServer() {
      var self = this;
      self.$refs['serverForm'].validate((valid) => {
        if (valid) {
          add_server(self.serverForm.index, self.serverForm.label, self.serverForm.host, self.serverForm.port, self.serverForm.user, self.serverForm.password)
          .then(res => {
            self.serverList = res;
            self.showCreateServer = false;
            this.serverForm = {};
          }, (err) => {
            this.$message.error(err);
          });
        }
      });
    },
    editServer(data) {
      const index = this.serverList.findIndex(function(item) {
        if (item.label === data.label) {
          return true;
        }
      });
      this.serverForm = JSON.parse(JSON.stringify(data));
      this.serverForm.index = index;
      this.showCreateServer = true;
    },
    deleteServer(data) {
      this.$confirm('确定删除 '+data.label+' 吗？').then(() => {
        const index = this.serverList.findIndex(function(item) {
          if (item.label === data.label) {
            return true;
          }
        });
        del_server(index).then(() => {
          this.serverList.splice(index, 1);
        }, (err) => {
          this.$message.error(err);
        });
      });
    },
    //连接server执行show databases
    connectServer() {
      let data = this.serverList[this.selectedNode];
      this.currentServerName = data.label;
      db_list(data.host, data.port, data.user, data.password).then(res => {
        let list = [];
        for (let i = 0; i < res.length; i++) {
          list.push({
            label: res[i]
          });
        }
        this.dbList = list;
        this.dbListFilter = list;
        this.filterDb = '';
        this.selectedNode = -1;
        this.showServerList = false;
        this.showDbList = true;
      }, (err) => {
        this.$message.error(err);
      });
      
    },
    //连接数据库
    connectDb() {
      let data = this.dbListFilter[this.selectedNode];
      this.create_db_connection(data.label);
      this.showDbList = false;
    },
    //切换数据库
    clickDb() {
      let db = this.databases[this.currentDbIndex];
      this.editTabs = db.tab;
      this.editTabsValue = db.lastTabsValue;
      this.filterText = db.filterText;
      let tab = this.getCurrEditTab();
      this.currentTableName = tab.tableName;
    },
    //切换表
    clickTable(node) {
      this.currentTableName = node.name
      let db = this.databases[this.currentDbIndex];
      this.editTabs = db.tab;
      let length = this.editTabs.length;
      if (length === 0) {
        this.editTabsValue = '1';
      }else{
        this.editTabsValue = (this.editTabs[length - 1].name + 1) + '';
      }
      let sql = 'SELECT * FROM ' + this.currentTableName;
      this.editTabs.push({
        type: EditTabType.SQL,
        title: this.currentTableName,
        name: this.editTabsValue,
        sql: sql,
        resultColumns: [],
        result: [],
        total: 0,
        page: 1,
        pagesize: 25,
        allow_edit: 0,
        tableName: this.currentTableName,
        primary_key: [],
        tableColumns: [],
        tableIndexs: [],
        addColumnNum: 1,
        addColumnAfter: '',
        updateForm: {nullable: {}, row: {}, new: {}},
      });
      db.lastTabsValue = this.editTabsValue;
      this.execute(1);
    },
    //切换sql界面
    clickTab() {
      let db = this.databases[this.currentDbIndex];
      db.lastTabsValue = this.editTabsValue;
      let tab = this.getCurrEditTab();
      this.currentTableName = tab.tableName;
    },
    //关闭sql界面
    removeTab(targetName) {
      let tabs = this.editTabs;
      let activeName = this.editTabsValue;
      let nextTab;
      if (activeName === targetName) {
        tabs.forEach((tab, index) => {
          if (tab.name === targetName) {
            nextTab = tabs[index + 1] || tabs[index - 1];
          }
        });
      }
      
      if (nextTab) {
        this.editTabsValue = nextTab.name;
        this.currentTableName = nextTab.tableName;
      }
      this.editTabs = tabs.filter(tab => tab.name !== targetName);
      let db = this.databases[this.currentDbIndex];
      db.tab = this.editTabs;
    },
    //新建表
    addTable() {
      let db = this.databases[this.currentDbIndex];
      let tableForm = JSON.parse(JSON.stringify(TableForm));
      for (let i = 0; i < 3; i++) {
        tableForm.columns.push(JSON.parse(JSON.stringify(ColumnForm)));
      }
      let length = this.editTabs.length;
      if (length === 0) {
        this.editTabsValue = '1';
      }else{
        this.editTabsValue = (this.editTabs[length - 1].name + 1) + '';
      }
      this.editTabs.push({
        type: EditTabType.TABLE,
        title: '新建表',
        name: this.editTabsValue,
        tableForm: tableForm,
        tableInfoSwitch: true,
        tableName: '',
      });
      db.lastTabsValue = this.editTabsValue;
      this.currentTableName = '';
    },
    //保存表结构
    createOrAlterTable(preview) {
      let editTabs = this.getCurrEditTab();
      let db = this.databases[this.currentDbIndex];
      if (this.currentTableName.length === 0) {
        const group = Collation.find(group => group.options.some(item => item === editTabs.tableForm.collation));
        if (!group) {
          this.$message.error('字符集不能为空');
          return;
        }
        editTabs.tableForm.charset = group.label;
        if(preview){
          create_table_preview(JSON.stringify(editTabs.tableForm)).then(res => {
            this.$alert(res, '预览Sql', {
              confirmButtonText: '确定'
            });
            console.log(res);
          });
        }else{
          create_table(db.host, db.name, JSON.stringify(editTabs.tableForm)).then(() => {
            this.refreshDB(db.name);
            this.clickTable({name: editTabs.tableForm.name});
            this.removeTab(editTabs.name);
            this.$message.success('创建成功');
          }, (err) => {
            this.$message.error(err);
          });
        }
        
      } else {
        editTabs.tableForm.name = this.currentTableName;
        const self = this;
        if(preview){
          alter_table_preview(JSON.stringify(editTabs.tableForm)).then(res => {
            this.$alert(res, '预览Sql', {
              confirmButtonText: '确定'
            });
            console.log(res);
          });
        }else{
          alter_table(db.host, db.name, JSON.stringify(editTabs.tableForm)).then(() => {
            self.tab_operate(EditTabType.STRUCTURE);
            this.$message.success('保存成功');
          }, (err) => {
            this.$message.error(err);
          });
        }
      }
    },
    //增加字段
    addColumn(index) {
      if (this.currentTableName) {
        return;
      }
      let editTabs = this.getCurrEditTab();
      let columns = editTabs.tableForm.columns;
      if (index === (columns.length - 1)) {
        columns.push(JSON.parse(JSON.stringify(ColumnForm)));
      }
    },
    refreshDB(database) {
      var self = this;
      let conf = {};
      for (let i = 0; i < this.serverList.length; i++) {
        if (this.serverList[i].label === this.currentServerName) {
          conf = this.serverList[i];
          break;
        }
      }
      connect_db(conf.host, conf.port, conf.user, conf.password, database).then(res => {
        let tables = [];
        for (let i = 0; i < res.length; i++) {
          tables.push({
            id: i,
            name: res[i]
          });
        }
        self.databases[self.currentDbIndex].tables = tables;
        self.databases[self.currentDbIndex].tableFilter = tables;
      }, (err) => {
        this.$message.error(err);
      });
    },
    create_db_connection(database) {
      var self = this;
      let conf = {};
      for (let i = 0; i < this.serverList.length; i++) {
        if (this.serverList[i].label === this.currentServerName) {
          conf = this.serverList[i];
          break;
        }
      }
      connect_db(conf.host, conf.port, conf.user, conf.password, database).then(res => {
        let tables = [];
        for (let i = 0; i < res.length; i++) {
          tables.push({
            id: i,
            name: res[i]
          });
        }
        self.databases.push({ 
          host: conf.host,
          name: database,
          alias: database,
          lastTabsValue: '1',
          tables: tables,
          tableFilter: tables,
          tab: [],
          filterText: ''
        });
        self.currentDbIndex = (self.databases.length - 1) + '';
        self.editTabs = [];
        self.filterText = '';
      }, (err) => {
        this.$message.error(err);
      });
    },
    closeDb() {
      this.databases.splice(this.currentDbIndex, 1);
      if (this.databases.length === 0) {
        this.currentDbIndex = '0';
        this.getServerList();
      } else {
        if (!this.databases[this.currentDbIndex]) {
          this.currentDbIndex = (this.databases.length - 1) + '';
        }
        this.clickDb();
      }
    },
    //数据库标签重命名
    dbAlias() {
      var self = this;
      let db = self.databases[this.currentDbIndex];
      this.$prompt('', '重命名标签', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        inputValue: db.alias,
        inputPattern: /[^\s]+/,
        inputErrorMessage: '格式错误'
      }).then(({ value }) => {
        db.alias = value;
      }).catch(() => {});
    },
    //执行sql命令
    execute(page) {
      let self = this;
      let db = this.databases[this.currentDbIndex];
      let editTabs = this.getCurrEditTab();
      if (page > 0) {
        editTabs.page = page;
      }
      execute_sql(db.host, db.name, editTabs.sql, editTabs.pagesize, editTabs.page).then(res => {
        editTabs.result = res.data;
        editTabs.resultColumns = res.columns;
        editTabs.total = res.total;
        editTabs.allow_edit = res.allow_edit;
        editTabs.primary_key = res.primary_key;
        if (res.table_name.length > 0) {
          editTabs.tableName = res.table_name;
          editTabs.title = res.table_name;
          self.currentTableName = res.table_name;
        }
      }, (err) => {
        this.$message.error(err);
      });
    },
    cellDbClick(event, allow_edit, row, column, index) {
      const { pageX, pageY } = event;
      this.overlay = {
        position: 'absolute',
        left: `${pageX}px`,
        top: `${pageY}px`
      };
      this.tableEditor = {
        index: index,
        column: column,
        oldValue: row[column][1],
        newValue: row[column][1],
        row: row,
        allowEdit: allow_edit,
        valueNull: row[column][0] == 'NULL'
      };
    },
    // 触发更新单元格
    tableEdit() {
      // var self = this;
      let sql = '';
      let row = this.tableEditor.row;
      let column = this.tableEditor.column;
      let newValue = '';
      if(this.tableEditor.allowEdit == 0){
        return;
      }
      if (row[column][0] == 'NULL' && this.tableEditor.valueNull){
        return;
      }
      if (this.tableEditor.valueNull) {
        newValue = "NULL";
      } else if(this.tableEditor.newValue != this.tableEditor.oldValue){
        newValue = "'" + this.escapeString(this.tableEditor.newValue) + "'";
      }
      if (newValue != '') {
        let editTabs = this.getCurrEditTab();
        let primary_key = editTabs.primary_key;
        if (primary_key.length === 0) {
          this.$message.error("查询结果不包含主键");
        } else {
          sql = "UPDATE " + this.currentTableName + " SET " + column + " = " + newValue + " WHERE ";
          for (let i = 0; i < primary_key.length; i++) {
            if (i != 0) {
              sql += " AND ";
            }
            sql += primary_key[i] + " = " + row[primary_key[i]][1];
          }
          let db = this.databases[this.currentDbIndex];
          execute_sql(db.host, db.name, sql).then(() => {
            this.execute(0);
            this.$message.success("更新成功.");
          }, (err) => {
            this.$message.error(err);
          });
        }
      }
    },
    handleEscape() {
      const { column, row, oldValue } = this.tableEditor;
      row[column][1] = oldValue;
      this.tableEditor.index = -1;
    },
    handleClickOutside(event) {
      if (!event.target.closest('.overlay') && this.tableEditor.index != -1){
        this.tableEdit();
        this.tableEditor.index = -1;
      }
    },
    getCurrEditTab() {
      let editTabs = {};
      for (let i = 0; i < this.editTabs.length; i++) {
        if (this.editTabs[i].name === this.editTabsValue) {
          editTabs = this.editTabs[i];
        }
      }
      return editTabs;
    },
    handleSizeChange(val) {
      let editTabs = this.getCurrEditTab();
      editTabs.pagesize = val;
      this.execute(1);
    },
    tableWidth(str) {
      let len = str.length;
      if (len < 5) {
        return len * 30;
      } else if (len < 10) {
        return len * 20;
      } else if (len < 15) {
        return len * 15;
      } else if (len < 20) {
        return len * 10;
      } else {
        return len * 8;
      }
    },
    tab_operate(type, row) {
      let editTabs = this.getCurrEditTab();
      let db = this.databases[this.currentDbIndex];
      let updateForm = {nullable: {}, row: {}, new: {}};
      editTabs.type = type;
      if (type == EditTabType.UPDATE || type == EditTabType.STRUCTURE) {
        table_index(db.host, db.name, editTabs.tableName).then(res => {
          console.log(res);
          let indexs = [];
          let last = {};
          res.map(item => {
            if(item.Seq_in_index == 1){
              if (last.Key_name){
                indexs.push(last);
              }
              last = item;
            } else {
              last.Column_name += ',' + item.Column_name;
            }
          });
          indexs.push(last);
          editTabs.tableIndexs = indexs;
        }, (err) => {
          this.$message.error(err);
        });
        table_columns(db.host, db.name, editTabs.tableName).then(res => {
          let kres = {};
          for (let i = 0; i < res.length; i++) {
            kres[res[i].name] = res[i];
            if (res[i].default != null && res[i].default.length > 0) {
              updateForm.new[res[i].name] = res[i].default;
            } 
          }
          if (row) {
            for (const key in row) {
              updateForm.nullable[key] = "String";
              if (row[key][0] == "String") {
                updateForm.new[key] = row[key][1];
              } else {
                updateForm.new[key] = '';
                if (kres[key].nullable == "YES") {
                  updateForm.nullable[key] = "NULL";
                }
              }
            }
            updateForm.row = row;
          }
          editTabs.updateForm = updateForm;
          editTabs.tableColumns = res;
          editTabs.addColumnAfter = res[res.length - 1].name
        }, (err) => {
          this.$message.error(err);
        });
      }
    },
    updateOrInsert() {
      let editTabs = this.getCurrEditTab();
      let db = this.databases[this.currentDbIndex];
      let sql = '';
      const { updateForm, primary_key, tableColumns } = editTabs;
      // insert
      if (Object.keys(updateForm.row).length === 0) {
        sql = "INSERT INTO `" + this.currentTableName + "` ";
        let columns = '';
        let values = '';
        for (let i = 0; i < tableColumns.length; i++) {
          const key = tableColumns[i].name;
          columns += "`" + key + "`,";
          if (updateForm.nullable[key] == "NULL") {
            values += "NULL,";
          } else if (updateForm.new[key]) {
            let _v = updateForm.new[key] == "CURRENT_TIMESTAMP" ? "CURRENT_TIMESTAMP" : "'" + this.escapeString(updateForm.new[key]) + "'";
            values += _v + ",";
          } else {
            values += "'',";
          }
        }
        sql += "(" + columns.substring(0, columns.length - 1) + ") VALUES (" + values.substring(0, values.length - 1) + ");";
        
      } else { //update
        let where = '';
        let val = '';
        let row = JSON.parse(JSON.stringify(updateForm.row));
        for (const key in row) {
          if (row[key][0] == "NULL") {
            row[key][1] = "";
          }
        }
        for (const key in updateForm.new) {
          if (updateForm.new[key] != row[key][1] || row[key][0] != updateForm.nullable[key]) {
            if (updateForm.nullable[key] == "NULL") {
              val += "`" + key + "` = NULL,";
            } else {
              let _v = updateForm.new[key] == "CURRENT_TIMESTAMP" ? "CURRENT_TIMESTAMP" : "'" + this.escapeString(updateForm.new[key]) + "'";
              val += "`" + key + "`= " + _v + ",";
            }
          }
        }
        val = val.substring(0, val.length - 1);
        if (val.length === 0) {
          editTabs.type = EditTabType.SQL;
          return;
        }
        for (let i = 0; i < primary_key.length; i++) {
          if (i != 0) {
            where += " AND ";
          }
          where += primary_key[i] + " = " + row[primary_key[i]][1];
        }
        sql = "UPDATE " + this.currentTableName + " SET " + val + " WHERE " + where;
      }
      execute_sql(db.host, db.name, sql).then(() => {
        this.execute(0);
        editTabs.type = EditTabType.SQL;
        this.$message.success("更新成功.");
      }, (err) => {
        this.$message.error(err);
      });
    },
    deleteRow(row) {
      let editTabs = this.getCurrEditTab();
      let db = this.databases[this.currentDbIndex];
      let primary_key = editTabs.primary_key;
      let sql = "DELETE FROM `" + this.currentTableName + "` WHERE ";
      for (let i = 0; i < primary_key.length; i++) {
        if (i != 0) {
          sql += " AND ";
        }
        sql += primary_key[i] + " = " + row[primary_key[i]][1];
      }
      this.$confirm('确定执行 ' + sql + ' 吗？').then(() => {
        execute_sql(db.host, db.name, sql).then(() => {
          this.execute(0);
          this.$message.success("删除成功.");
        }, (err) => {
          this.$message.error(err);
        });
      });
    },
    editColumn(row) {
      let db = this.databases[this.currentDbIndex];
      let editTabs = this.getCurrEditTab();
      table_columns(db.host, db.name, editTabs.tableName, row.name).then(res => {
        editTabs.type = EditTabType.TABLE;
        editTabs.tableInfoSwitch = false;
        let tableForm = JSON.parse(JSON.stringify(TableForm));
        let value;
        let definedValue = '';
        if (res[0].default == null) {
          if (res[0].nullable == 'YES') {
            value = 'NULL';
          } else {
            value = 'NONE';
          }
        } else if (res[0].extra.indexOf('CURRENT_TIMESTAMP') > -1) {
          value = 'CURRENT_TIMESTAMP';
        } else if (res[0].default != null) {
          value = 'DEFINED';
          definedValue = res[0].default;
        } else {
          value = 'NONE';
        }
        
        let length = '';
        if (res[0].type.match(/\(.*\)/)) {
          length = res[0].type.match(/\(.*\)/)[0].replace(/\(|\)/g, '');
        }

        let attribute = '';
        if (res[0].extra.indexOf('on update CURRENT_TIMESTAMP') > -1) {
          attribute = 'on update CURRENT_TIMESTAMP';
        } else if (res[0].type.indexOf('unsigned zerofill') > -1) {
          attribute = 'UNSIGNED ZEROFILL';
        } else if (res[0].type.indexOf('unsigned') > -1) {
          attribute = 'UNSIGNED';
        }

        tableForm.operate = 'CHANGE';
        tableForm.columns.push({
            name: res[0].name,
            old_name: res[0].name,
            type: res[0].data_type,
            length: length,
            value: value,
            definedValue: definedValue,
            attribute: attribute,
            null: res[0].nullable == 'YES' ? '1' : '0',
            primary: res[0].key == 'PRI' ? '1' : '0',
            auto_increment: res[0].extra.indexOf('auto_increment') > -1 ? '1' : '0',
            comment: res[0].comment
          });
        editTabs.tableForm = tableForm;
      }, (err) => {
        this.$message.error(err);
      });
    },
    delColumn(row) {
      let db = this.databases[this.currentDbIndex];
      let sql = "ALTER TABLE `" + this.currentTableName + "` DROP `" + row.name + "`;";
      const self =  this;
      this.$confirm('确定执行 ' + sql + ' 吗？').then(() => {
        execute_sql(db.host, db.name, sql).then(() => {
          self.tab_operate(EditTabType.STRUCTURE);
          this.$message.success("删除成功.");
        }, (err) => {
          this.$message.error(err);
        });
      });
    },
    addColumnSelect(data) {
      let res = [];
      data.map(function(item) {
        res.push({name: item.name, label: '于 ' + item.name + ' 之后'});
      });
      return res;
    },
    addColumnAfter() {
      let editTabs = this.getCurrEditTab();
      let tableForm = JSON.parse(JSON.stringify(TableForm));
      for (let i = 0; i < editTabs.addColumnNum; i++) {
        let from = JSON.parse(JSON.stringify(ColumnForm));
        from.after = editTabs.addColumnAfter;
        tableForm.columns.push(from);
      }
      tableForm.operate = 'ADD';
      editTabs.tableForm = tableForm;
      editTabs.type = EditTabType.TABLE;
      editTabs.tableInfoSwitch = false;
    },
    escapeString(value) {
      return value.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '\\"');
    },
    alert() {
      this.$alert('功能正在完善中', '提示', {
        confirmButtonText: '确定'
      });
    }
  },
}
</script>

<style>
.connect_tree_node {
  width: 100%;
  height: 36px;
  line-height: 36px;
  border-radius: 5px;
  cursor: pointer;
}
.connect_tree_node.selected {
  background-color:#1c57e0;
  color: #fff;
}
.connect_tree_node.selected i {
  color: #fff;
}
.db_tree_icon {
  color: #3c66ba;
  margin: 0 5px 0 20px;
}
.connect_list {
  height: 300px;
  overflow: scroll;
}
.connect_list .el-tree-node__content  {
  height: 36px;
}
.connect_tree_node {
  width: 100%;
}
.connect_tree_node .el-link {
  font-size: 16px;
}
.connect_tree_opt_right {
  float: right;
}
.connect_tree_opt_right .opt_item {
  margin-right: 20px;
}
.table_menu {
  width: 200px;
  background-color: #f1f1f1;
}
.table_menu div {
  height: 26px;
  line-height: 26px;
}
.el-tree, .el-link--inner {
  color: #222222;
}
.el-table thead {
  color: #222222;
}
.el-table.datatable.result {
  overflow: initial;
}
.el-table.datatable.result th {
  font-weight: 100;
  background-color: #f9f9f9;
  text-shadow: 0 1px 0 #fff;  
}
.el-table.datatable.result .el-table__header-wrapper {
  position: sticky;
  top: 0;
  z-index: 999;
}
.el-table.datatable.result thead {
  color: #409eff;
}
.el-table.datatable.result .el-button span {
  font-weight: 250;
}
.datatable {
  width: 100%;
  margin-top: 10px;
}
.datatable .el-table__body td {
  vertical-align: top;
}
.edit_tab_btn {
  margin: 0 0 15px 5px;
}
.descStyle {
  color: #222222;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all;
  display: -webkit-box;
  -webkit-box-orient: vertical;
}
.descStyle.is_null {
  color: #c3c3c3;
  font-style: italic;
}
.overlay {
  position: absolute;
  background: white;
  border: 1px solid #ccc;
  padding: 10px;
  z-index: 1000;
  width: 300px;
  font-size: 14px;
  color: #c3c3c3;
}
.CodeMirror {
  height: 150px;
}
.submit_btn {
  margin: 5px;
}
.altertable {
  color: #222222;
  font-size: 14px;
}
.altertable .el-tooltip span {
  text-decoration: underline;
}
.altertable .el-button--text span {
  font-weight: 250;
}
</style>